import * as Cesium from "cesium";
import type { FixedLengthArray } from "@utils"
export interface FlyToBoundingSphereType {
  boundary: FixedLengthArray<number, 3>,
  pitch: number
  scaleFactor: number
}
/**
 * 将相机飞向指定的包围球，并自动调整相机位置和视角。
 * 
 * @param {Object} options - 配置选项
 * @param {Array} options.boundary - 边界点数组，每两个元素表示一个经纬度坐标
 * @param {Number} options.pitch - 相机俯仰角（以度为单位）
 * @param {Number} [options.scaleFactor=0.5] - 缩放因子，用于调整目标的观察大小
 * @returns {Promise} - 返回一个Promise对象，在相机飞行完成后解析
 * 
 * @example // 使用示例
        flyToBoundingSphere({
            boundary:[116.3913, 39.9075, 116.4013, 39.9175], // 北京坐标示例
            pitch: 45, // 设置俯仰角为45度
            scaleFactor: 0.7 // 缩小视图中的物体大小
        }).then(() => {
            console.log('相机飞行完成');
        }).catch(error => {
            console.error('相机飞行失败:', error);
        });
 */
const flyToBoundingSphere = (viewer: Cesium.Viewer, options: FlyToBoundingSphereType) => {
  new Promise((resolve, reject) => {
    try {
      const { boundary, pitch, scaleFactor = 0.5 } = options;

      const boundingSphere = getBoundingSphere(boundary);

      // 调整包围球的半径，根据 scaleFactor 放大或缩小视图中的物体大小
      boundingSphere.radius *= 1 / scaleFactor;
      // 计算合适的相机高度
      const distance =
        boundingSphere.radius / Math.sin((viewer.camera.frustum as any).fov / 2);

      // 自动调整相机以确保包围球在视野内
      viewer.camera.flyToBoundingSphere(boundingSphere, {
        duration: 2, // 单位秒
        offset: new Cesium.HeadingPitchRange(
          Cesium.Math.toRadians(360),
          Cesium.Math.toRadians(pitch), // 设置相机俯仰角
          distance, // 计算合适的距离
        ),
        complete: () => {
          resolve({});
        },
      });
    } catch (e) {
      reject(e);
    }
  })
}
/**
 * 计算包含指定边界点的包围球。
 *
 * @param {Array} boundary - 边界点数组，每两个元素表示一个经纬度坐标
 * @returns {Cesium.BoundingSphere} - 包围球对象
 */
const getBoundingSphere = (boundary: FixedLengthArray<number, 3>) => {
  // 将边界点转换为 Cartesian3 坐标
  const positions = [];
  for (let i = 0; i < boundary.length; i += 2) {
    const lon = boundary[i];
    const lat = boundary[i + 1];
    const position = Cesium.Cartesian3.fromDegrees(lon, lat);
    positions.push(position);
  }

  // 计算包含所有边界点的包围球
  return Cesium.BoundingSphere.fromPoints(positions);
}
export interface FlyToType {
  position: FixedLengthArray<number, 3>,
  orientation?: any;
  duration?: number;
  complete?: Cesium.Camera.FlightCompleteCallback;
  cancel?: Cesium.Camera.FlightCancelledCallback;
  endTransform?: Cesium.Matrix4;
  maximumHeight?: number;
  pitchAdjustHeight?: number;
  flyOverLongitude?: number;
  flyOverLongitudeWeight?: number;
  convert?: boolean;
  easingFunction?: Cesium.EasingFunction.Callback;
}
const flyTo = (viewer: Cesium.Viewer, options: FlyToType) => {
  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(...options.position),
    orientation: options.orientation,
    duration: options.duration,
    complete: options.complete,
    cancel: options.cancel,
    endTransform: options.endTransform,
    maximumHeight: options.maximumHeight,
    pitchAdjustHeight: options.pitchAdjustHeight,
    flyOverLongitude: options.flyOverLongitude,
    flyOverLongitudeWeight: options.flyOverLongitudeWeight,
    convert: options.convert,
    easingFunction: options.easingFunction
  })
}
export interface LookAtType {
  position: FixedLengthArray<number, 3>,
  offset: Cesium.Cartesian3 | Cesium.HeadingPitchRange,
}
const lookAt = (viewer: Cesium.Viewer, options: LookAtType) => {
  viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(...options.position), options.offset);
}
export interface SetViewType {
  position: FixedLengthArray<number, 3>,
  orientation?: Cesium.HeadingPitchRollValues | Cesium.DirectionUp;
  endTransform?: Cesium.Matrix4;
  convert?: boolean;
}
const setView = (viewer: Cesium.Viewer, options: SetViewType) => {
  viewer.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(...options.position),
    orientation: options.orientation,
    endTransform: options.endTransform,
    convert: options.convert
  });
}
export {
  flyToBoundingSphere,
  flyTo,
  lookAt,
  setView
}